package com.xnx.bincker.leader.core.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xnx.bincker.leader.exception.permission.NoLoginException;
import com.xnx.bincker.leader.exception.permission.PermissionDeniedException;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Service;

import java.util.Collection;

@Service
@Log4j2
public class AccessDecisionManager implements org.springframework.security.access.AccessDecisionManager {
    final
    ObjectMapper objectMapper;

    @Autowired
    public AccessDecisionManager(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
        if(collection.isEmpty()) return;
        for (ConfigAttribute configAttribute : collection) {
            for (GrantedAuthority authority : authentication.getAuthorities()) {
                if(authority.getAuthority().equals(configAttribute.getAttribute())) return ;
            }
        }
        AccessDeniedException exception;
        if(authentication.getPrincipal().equals("anonymousUser")){
            exception = new NoLoginException();
        }else{
            exception = new PermissionDeniedException();
        }
//        手动设置请求异常内容，不设置则在ErrorController中取不到异常
        FilterInvocation filterInvocation = (FilterInvocation) o;
        filterInvocation.getRequest().setAttribute(DefaultErrorAttributes.class.getName() + ".ERROR", exception);
        throw exception;
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}
